//
//  OneWay.m
//  PezMonkey
//
//  Created by Spence DiNicolantonio on 12/26/09.
//  Copyright 2009 Necrosoft. All rights reserved.
//

#import "OneWay.h"

#define kOneWayPlatformCollisionType 1
#define kOneWayBallCollisionType 2
#define kOneWayPlatformCollisionGroup 1


@implementation OneWay

@synthesize staticBody;

- (NSString *)demoName {
	return @"One Way";
}

- (void)start {
	// create space
	self.space = [PMSpace spaceWithGravity:PMVectMake(0, -1)];
	[space setSubSteps:3];
	[space setIterations:10];
	[space setPassThroughEnabled:YES];
	
	// initialize shared static body
	self.staticBody = [PMBody staticBody];
	
	// create screen boundary
	[self addScreenBoundary];
	
	
	PMBody *body;
	PMShape *shape;
	
	// create one-way segment
	PMFloat segHeight = 300;
	PMFloat segLength = 320;
	PMFloat segWidth = 20;
	shape = [PMSegmentShape segmentShapeWithBody:staticBody 
										   start:PMVectMake(-segLength/2, segHeight - 480/2) 
											 end:PMVectMake(segLength/2, segHeight - 480/2)
										   width:segWidth];
	[shape setFriction:1.0];
	[shape setElasticity:1.0];
	[shape setCollisionType:kOneWayPlatformCollisionType];
	[shape setLayers:PMLayerMaskNotGrabbable];
	[shape setCollisionGroup:kOneWayPlatformCollisionGroup];
	[shape setPassThrough:PMVectMake(0, 1)];
	[space addShape:shape];

	
	
	// define ball attributes
	PMFloat ballMass = 2.0;
	PMFloat ballRadius = 15.0;
	PMFloat ballMoment = PMMomentForCircle(ballMass, 0, ballRadius, PMVectZero);
	
	// create ball body
	body = [PMBody bodyWithMass:ballMass 
						 moment:ballMoment];
	[body setPosition:PMVectMake(0, 0)];
	//[body setVelocity:PMVectMake(0, -900)];
	[space addBody:body];
	
	// create ball shape
	shape = [PMCircleShape circleShapeWithBody:body 
										radius:ballRadius];
	[shape setFriction:0.9];
	[shape setElasticity:0.3];
	[shape setCollisionType:kOneWayBallCollisionType];
	[space addShape:shape];
	
	
	
	// define springboard attributes
	PMFloat sbHeight = 120;
	PMFloat sbWidth = 10;
	PMFloat sbLength = (sbWidth + ballRadius)*2 + 1;
	PMFloat sbLipHeight = 30;
	PMFloat sbMass = 4;
	PMVect sbPosition = PMVectMake(0, sbHeight - 480/2);
	
	// define springboard vertices
	PMFloat sbVertCount = 4;
	PMVect sbVerts[] = {
		PMVectMake(-sbLength/2, -sbWidth/2),
		PMVectMake(-sbLength/2, sbWidth/2),
		PMVectMake(sbLength/2, sbWidth/2),
		PMVectMake(sbLength/2, -sbWidth/2)
	};
	PMFloat sbMoment = PMMomentForPolygon(sbMass, sbVerts, sbVertCount, PMVectZero);
	
	// define springboard lip vertices
	PMFloat sbLipVertCount = 4;
	PMVect sbLeftLipVerts[] = {
		PMVectMake(-sbLength/2, sbWidth/2),
		PMVectMake(-sbLength/2, sbWidth/2 + sbLipHeight),
		PMVectMake(sbWidth - sbLength/2, sbWidth/2 + sbLipHeight),
		PMVectMake(sbWidth - sbLength/2, sbWidth/2)
	};
	PMVect sbRightLipVerts[] = {
		PMVectMake(sbLength/2 - sbWidth, sbWidth/2),
		PMVectMake(sbLength/2 - sbWidth, sbWidth/2 + sbLipHeight),
		PMVectMake(sbLength/2, sbWidth/2 + sbLipHeight),
		PMVectMake(sbLength/2, sbWidth/2),
	};
	
	// create springboard body
	PMBody *springboard = [PMBody bodyWithMass:sbMass moment:sbMoment];
	[springboard setPosition:sbPosition];
	[space addBody:springboard];
	
	// create springboard shape
	shape = [PMPolygonShape polygonShapeWithBody:springboard 
										vertices:sbVerts 
									   vertCount:sbVertCount];
	[shape setFriction:1];
	[shape setElasticity:0];
	[shape setCollisionGroup:kOneWayPlatformCollisionGroup];
	[space addShape:shape];
	shape = [PMPolygonShape polygonShapeWithBody:springboard 
										vertices:sbLeftLipVerts 
									   vertCount:sbLipVertCount];
	[shape setFriction:1];
	[shape setElasticity:0];
	[shape setCollisionGroup:kOneWayPlatformCollisionGroup];
	[space addShape:shape];
	shape = [PMPolygonShape polygonShapeWithBody:springboard 
										vertices:sbRightLipVerts 
									   vertCount:sbLipVertCount];
	[shape setFriction:1];
	[shape setElasticity:0];
	[shape setCollisionGroup:kOneWayPlatformCollisionGroup];
	[space addShape:shape];
	
	
	// add springs to springboard
	PMFloat springAnchorHeight = sbHeight + sbLipHeight + 40;
	PMFloat springLength = 5;
	PMFloat springStiffness = 110;
	PMFloat springDamping = 0.5;
	PMDampedSpring *spring;
	PMFloat x;
	PMFloat y;
	
	// left
	x = (sbWidth - sbLength)/2;
	y = sbLipHeight;
	spring = [PMDampedSpring dampedSpringWithAnchor:PMVectMake(x, y) 
											onBodyA:springboard
											 anchor:PMVectMake(x - 50, springAnchorHeight - 480/2)
											onBodyB:staticBody 
										 restLength:springLength 
										  stiffness:springStiffness 
											damping:springDamping];
	[space addConstraint:spring];
	
	// right
	x = (sbLength - sbWidth)/2;
	y = sbLipHeight;
	spring = [PMDampedSpring dampedSpringWithAnchor:PMVectMake(x, y) 
											onBodyA:springboard 
											 anchor:PMVectMake(x + 50, springAnchorHeight - 480/2)
											onBodyB:staticBody 
										 restLength:springLength 
										  stiffness:springStiffness 
											damping:springDamping];
	[space addConstraint:spring];
			
}

/**
 * Creates and segment shapes to demo space to make a boundary along the edges of
 * the screen.
 */
- (void)addScreenBoundary {
	// make sure static body has been initialized
	if (!staticBody)
		self.staticBody = [PMBody staticBody];
	
	// create temp shape
	PMShape *shape;
	
	// define boundary segment width 
	// (needs to be thick to avoid penetration at high velocities)
	PMFloat width = 30;
	
	// create left screen boundary
	shape = [PMSegmentShape segmentShapeWithBody:staticBody
										   start:PMVectMake(-320 - width/2, -240)
											 end:PMVectMake(-320 - width/2, 240)
										   width:width];
	[shape setElasticity:1.0];
	[shape setFriction:1.0];
	[shape setLayers:PMLayerMaskNotGrabbable];
	[space addStaticShape:shape];
	
	// create right screen boundary
	shape = [PMSegmentShape segmentShapeWithBody:staticBody
										   start:PMVectMake(320 + width/2, -240) 
											 end:PMVectMake(320 + width/2, 240)
										   width:width];
	[shape setElasticity:1.0];
	[shape setFriction:1.0];
	[shape setLayers:PMLayerMaskNotGrabbable];
	[space addStaticShape:shape];
	
	// create bottom screen boundary
	shape = [PMSegmentShape segmentShapeWithBody:staticBody
										   start:PMVectMake(-320, -240 - width/2) 
											 end:PMVectMake(320, -240 - width/2)
										   width:width];
	[shape setElasticity:1.0];
	[shape setFriction:1.0];
	[shape setLayers:PMLayerMaskNotGrabbable];
	[space addStaticShape:shape];
}

- (BOOL)callback:(PMCollision *)collision {
	return YES;
}


#pragma mark -
#pragma mark Dealloc

- (void)dealloc {
	[staticBody release];
	[super dealloc];
}

@end
